Banco de Dados

Aula 04 - Mapeamento e Normalização




Helder Jefferson Ferreira da Luz

helder.luz@ifpr.edu.br

Objetivos da aula

  • Mapeamento ER para Relacional: transformar o diagrama ER em um conjunto de tabelas.
  • Normalização:
    • Primeira Forma Normal (1FN)
    • Segunda Forma Normal (2FN)
    • Terceira Forma Normal (3FN)

Mapeamento do ER para o Banco de Dados

O Mapeamento ER para o Modelo Relacional é um conjunto de regras para converter nosso diagrama (modelo conceitual) em um esquema de tabelas (modelo lógico).

Regras Gerais:

  1. Cada entidade vira uma tabela.
  2. Cada atributo vira uma coluna nessa tabela.
  3. O identificador da entidade se torna a Chave Primária (PK) da tabela.

Mas... e os relacionamentos?

Mapeando Relacionamentos

A forma como um relacionamento vira parte do esquema de tabelas depende da sua cardinalidade.

  • Relacionamento 1:N (Um para Muitos)
  • Relacionamento 1:1 (Um para Um)
  • Relacionamento N:M (Muitos para Muitos)

Vamos ver cada caso.

Mapeando Relacionamentos 1:N

A tabela do lado "N" (muitos) recebe uma Chave Estrangeira (FK) que aponta para a chave primária da tabela do lado "1".

Exemplo: CLIENTE e PEDIDO

  • Um CLIENTE faz muitos PEDIDOS.
  • O lado "N" é PEDIDO.
  • A tabela PEDIDO ganha uma coluna id_cliente (FK) que referencia o id da tabela CLIENTE.

Mapeando Relacionamentos 1:1

É semelhante ao 1:N. Você pode escolher qual tabela receberá a Chave Estrangeira.

Recomendação: Coloque a FK na tabela que representa a entidade "dependente" ou que participa opcionalmente do relacionamento.

Exemplo: MOTORISTA e CNH

  • Uma CNH não existe sem um MOTORISTA.
  • A tabela CNH recebe a FK id_motorista.

Mapeando Relacionamentos N:M

Como já vimos, um relacionamento N:M é resolvido criando uma entidade associativa.

Regra: O relacionamento N:M vira uma nova tabela (tabela de junção).

  • As chaves primárias das duas tabelas originais se tornam Chaves Estrangeiras (FKs) na nova tabela.
  • A combinação dessas duas FKs geralmente forma a Chave Primária da nova tabela.

Exemplo: PEDIDO e PRODUTO

  • O relacionamento vira a tabela ITEM_PEDIDO.

Mapeando N:M - Exemplo

A chave primária de ITEM_PEDIDO é a combinação de (id_pedido, id_produto).

Normalização

Normalização é o processo de organizar as colunas e tabelas de um banco de dados para minimizar a redundância de dados e evitar anomalias.


Anomalias são problemas que ocorrem ao inserir, atualizar ou deletar dados.

Normalização - anomalias

Exemplos:

  • Anomalia de Inserção: Não consigo adicionar um dado porque me falta outro. (Ex: Não posso cadastrar um autor se ele ainda não tiver um livro publicado).
  • Anomalia de Atualização: Tenho que atualizar a mesma informação em vários lugares. (Ex: Mudar o nome de um autor em todos os 10 livros dele).
  • Anomalia de Exclusão: Apago um registro e perco informações que não queria perder. (Ex: Apago o único livro de um autor e perco os dados do autor junto).

Normalização

Há 3 regras principais para normalização do banco de dados. Cada regra é chamada de "forma normal".

Se a primeira regra for observada, diz-se que o banco de dados está na "primeira forma normal".
Se as três primeiras regras forem observadas, o banco de dados será considerado na "terceira forma normal".

Embora outros níveis de normalização sejam possíveis, a terceira forma normal é considerada o nível mais alto necessário para a maioria dos aplicativos.

As Formas Normais (FN)

  • 1FN (Primeira Forma Normal): A regra mais básica.
  • 2FN (Segunda Forma Normal): Requer que a 1FN seja atendida.
  • 3FN (Terceira Forma Normal): Requer que a 2FN seja atendida.

Um bom modelo ER geralmente já leva a um esquema em 3FN!

1FN: Sem valores múltiplos

Regra: Os valores em cada coluna de uma tabela devem ser atômicos (indivisíveis) e não deve haver grupos de repetição.

Problema: Uma coluna telefone que armazena "(41) 9999-8888, (41) 3333-4444".
Solução: Crie uma nova tabela TELEFONE_CLIENTE para armazenar os telefones.

1FN: Sem valores múltiplos

Exemplo:

Antes (ERRADO):

id_cliente nome telefones
1 João "9999-8888, 8888-9999"

Depois (CORRETO):
Tabela CLIENTE:

id_cliente nome
1 João

Tabela TELEFONE_CLIENTE:

id_cliente telefone
1 "9999-8888"
1 "8888-9999"

2FN: Dependência total da chave

Regra: Todos os atributos não-chave devem depender completamente da chave primária.

Problema: Na nossa tabela ITEM_PEDIDO(id_pedido PK, id_produto PK, nome_produto, quantidade).

  • quantidade depende de (id_pedido, id_produto). OK.
  • nome_produto depende apenas de id_produto. Isso viola a 2FN!

Solução: Mover nome_produto para a tabela PRODUTO, onde ele pertence. O mapeamento ER correto já faz isso naturalmente!

3FN: Sem dependências transitivas

Regra: Nenhum atributo não-chave deve depender de outro atributo não-chave.

Problema: Tabela PEDIDO(id_pedido PK, id_cliente, nome_cliente).

  • id_cliente depende de id_pedido. OK.
  • nome_cliente depende de id_cliente.
  • Logo, nome_cliente depende de id_pedido por trânsito. Isso viola a 3FN!

Solução: Mover nome_cliente para a tabela CLIENTE. Novamente, um bom mapeamento ER já resolve isso.

Exemplo Prático de Normalização

Tabela Inicial (Não Normalizada): PEDIDOS_COMPLETOS

NumPedido Data IDCliente NomeCliente Itens (IDProduto, NomeProduto, Qtd)
101 25/10/25 C1 João Silva (P1, Caneta, 2), (P2, Caderno, 1)
102 25/10/25 C2 Maria Souza (P3, Lápis, 5)
103 26/10/25 C1 João Silva (P1, Caneta, 1)

Esta tabela tem vários problemas:

  • A coluna Itens armazena múltiplos valores (viola a 1FN).
  • NomeCliente se repete para o IDCliente C1 (redundância).
  • NomeProduto depende de IDProduto, não da chave do pedido (viola a 2FN).
  • NomeCliente depende de IDCliente, que não é a chave primária (viola a 3FN).

Aplicando a 1ª Forma Normal (1FN)

Regra: Eliminar grupos de repetição e garantir que cada coluna tenha um valor atômico.

Separa a coluna Itens em registros individuais, criando a tabela ITENS_PEDIDO.


Tabela PEDIDOS (Parcialmente corrigida)

NumPedido Data IDCliente NomeCliente
101 25/10/25 C1 João Silva
102 25/10/25 C2 Maria Souza
103 26/10/25 C1 João Silva

Tabela ITENS_PEDIDO (Nova)

NumPedido IDProduto NomeProduto Qtd
101 P1 Caneta 2
101 P2 Caderno 1
102 P3 Lápis 5
103 P1 Caneta 1

Chave Primária de ITENS_PEDIDO: (NumPedido, IDProduto)

Aplicando a 2ª Forma Normal (2FN)

Regra: Todos os atributos não-chave devem depender da chave primária inteira.

Na tabela ITENS_PEDIDO:

  • Qtd depende da chave inteira (OK).
  • NomeProduto depende apenas de IDProduto (Violação da 2FN).

Solução: Criar uma tabela PRODUTOS.

Tabela ITENS_PEDIDO (Corrigida)

NumPedido (FK) IDProduto (FK) Qtd
101 P1 2
101 P2 1
102 P3 5
103 P1 1

Tabela PRODUTOS (Nova)

IDProduto (PK) NomeProduto
P1 Caneta
P2 Caderno
P3 Lápis

Aplicando a 3ª Forma Normal (3FN)

Regra: Nenhum atributo não-chave pode depender de outro atributo não-chave.

Na tabela PEDIDOS, a chave é NumPedido.

  • IDCliente depende de NumPedido (OK).
  • NomeCliente depende de IDCliente.
  • Logo, NomeCliente tem uma dependência transitiva de NumPedido (Violação da 3FN).

Solução: Criar uma tabela CLIENTES.

Aplicando a 3ª Forma Normal (3FN)

Tabela PEDIDOS (Corrigida)

NumPedido (PK) Data IDCliente (FK)
101 25/10/25 C1
102 25/10/25 C2
103 26/10/25 C1

Tabela CLIENTES (Nova)

IDCliente (PK) NomeCliente
C1 João Silva
C2 Maria Souza

Resultado Final: Esquema Normalizado (3FN)

Após aplicar as 3 formas normais, saímos de uma tabela gigante e cheia de problemas para 4 tabelas organizadas, sem redundância e que evitam anomalias:

  • CLIENTES (IDCliente PK, NomeCliente)
  • PRODUTOS (IDProduto PK, NomeProduto)
  • PEDIDOS (NumPedido PK, Data, IDCliente FK)
  • ITENS_PEDIDO (NumPedido FK, IDProduto FK, Qtd)

Este é o poder da normalização! E, como vimos antes, um bom diagrama Entidade-Relacionamento já nos guiaria para este resultado desde o início.

Diagrama não normalizado

Diagrama normalizado 3FN

Desnormalização

É o processo de, intencionalmente, introduzir redundância em um banco de dados, desfazendo parte da normalização feita.

Motivação

  • Desempenho
    • Em bancos de dados muito grandes, unir (JOIN) muitas tabelas para buscar dados pode ser lento.
    • Para acelerar consultas (SELECT) que são muito frequentes, podemos adicionar colunas redundantes para evitar JOINs caros.

Desnormalização

Exemplo:

  • Em um sistema de e-commerce com milhões de pedidos, poderíamos adicionar a coluna nome_cliente na tabela PEDIDOS (violando a 3FN) para que a listagem de pedidos não precise fazer JOIN com a tabela CLIENTES toda vez.

Cuidado: A desnormalização deve ser usada com moderação e apenas quando há um ganho claro de performance, pois ela traz de volta os riscos de anomalias. É uma troca: complexidade de escrita/atualização por simplicidade/velocidade de leitura.

Dúvidas? 🤔

Exercícios

  1. Análise de normalização: A tabela funcionario_habilidades abaixo foi criada para registrar as habilidades de cada funcionário. Ela viola qual forma normal? Como você a corrigiria?
id_funcionario nome_funcionario habilidades
1 Carlos 'SQL, Python, Java'
2 Bruna 'Power BI, Excel'

Exercícios

  1. Análise de normalização: Considere a tabela alocacao_projetos. A chave primária é (id_projeto, id_participante). Identifique as violações e proponha um esquema corrigido.
id_projeto nome_projeto id_participante nome_participante cargo_participante horas_alocadas
P101 "Zeus" E5 Ana Analista Jr. 120
P101 "Zeus" E8 Pedro Programador Sr. 80
P102 "Apolo" E5 Ana Analista Jr. 90

Exercícios

  1. Análise de normalização: A tabela LIVROS armazena informações sobre livros e suas editoras. Qual forma normal ela viola e por quê? Normalize a estrutura.
id_livro titulo_livro id_editora nome_editora cidade_editora
L01 "SQL para Iniciantes" ED12 "Tech Books" São Paulo
L02 "A Arte da Normalização" ED12 "Tech Books" São Paulo

Exercícios

  1. Análise de Normalização: A tabela abaixo viola qual Forma Normal? Por quê? Como você a corrigiria?
    id_matricula id_aluno nome_aluno id_disciplina nome_disciplina
    101 1 Ana 5 Matemática
    102 1 Ana 6 Física

Esta é a regra mais importante!

```mermaid erDiagram CLIENTE ||--|{ PEDIDO : faz CLIENTE { int id PK string nome } PEDIDO { int id PK datetime data int id_cliente FK } ```

```mermaid erDiagram MOTORISTA ||--|| CNH : possui MOTORISTA { int id PK string nome } CNH { int numero PK date validade int id_motorista FK } ```

```mermaid erDiagram PEDIDO ||--|{ ITEM_PEDIDO : "contém" PRODUTO ||--|{ ITEM_PEDIDO : "é parte de" PEDIDO { int id PK datetime data } PRODUTO { int id PK string nome } ITEM_PEDIDO { int id_pedido FK int id_produto FK int quantidade } ```

*Esta regra só se aplica a tabelas com chaves primárias **compostas** (mais de uma coluna).*

Vamos pegar uma tabela "bagunçada" e aplicar as regras de normalização passo a passo.

```mermaid erDiagram PEDIDOS_COMPLETOS { int NumPedido PK "Chave Primária" date Data string IDCliente "Redundante com NomeCliente" string NomeCliente "Dependência transitiva" string "Itens(...)" "Atributo multivalorado, viola 1FN" } ```

```mermaid erDiagram CLIENTES ||--|{ PEDIDOS : "faz" PEDIDOS ||--|{ ITENS_PEDIDO : "contém" PRODUTOS ||--|{ ITENS_PEDIDO : "é item em" CLIENTES { string IDCliente PK string NomeCliente } PEDIDOS { int NumPedido PK date Data string IDCliente FK } PRODUTOS { string IDProduto PK string NomeProduto } ITENS_PEDIDO { int NumPedido FK string IDProduto FK int Qtd } ```

--- # Exercícios 1. **Mapeamento 1:N**: Você tem as entidades `CURSO` e `ALUNO`. Um curso tem muitos alunos, mas um aluno está em apenas um curso. Desenhe o diagrama ER (Crow's Foot) e descreva como ficariam as tabelas `CURSO` e `ALUNO` (colunas, PK e FK). 2. **Mapeamento N:M**: Agora, um `ALUNO` pode se matricular em muitas `DISCIPLINAS`, e uma disciplina pode ter muitos alunos. Desenhe o diagrama e descreva as **três** tabelas resultantes.

4. **Esquema da Loja**: Com base em tudo que vimos, escreva o esquema relacional final para o nosso projeto da loja, com as tabelas `CLIENTE`, `PEDIDO`, `PRODUTO` e `ITEM_PEDIDO`. Liste as colunas de cada uma, indicando PKs e FKs.

1FN pois há coluna multivalorada (habilidades) funcionario (id PK, nome) habilidade (id PK, nome) funcionario_habilidade (id_habilidade FK, id_funcionario FK)

2FN - nome_participante e cargo_participante dependem apenas de id_participante 2FN - nome_projeto depende apenas de id_projeto participante (id, nome, cargo) projeto (id, nome) projeto_participante(id_projeto FK, id_participante FK, horas_alocadas)

chave primária id_livro viola 3FN nome_editora e cidade_editora dependem apenas de id_editora, que não é chave livro (id, titulo) editora (id, nome, cidade) livro_editora (id_livro, id_editora)

chave primária parece ser id_matricula 3FN, nome_aluno depende de id_aluno, e por transição depende de id_matrícula. O mesmo paa nome_disciplina. matricula (id_matricula PK, id_aluno FK, id_disciplina FK) aluno (id PK, nome_aluno) disciplina (id PK, disciplina) | id_aluno | nome_aluno | | -------- | ---------- | | 1 | Ana | | id_disciplina | nome_disciplina | | ------------- | --------------- | | 5 | Matemática | | 6 | Física | | id_matricula | id_aluno | id_disciplina | | ------------ | -------- | ------------- | | 101 | 1 | 5 | | 102 | 1 | 6 |